\addtocontents{toc}{\vspace{\baselineskip}}
\begin{aosachapter}{Mercurial}{s:mercurial}{Dirkjan Ochtman}
%% Based on EN-Revision r229

%% Mercurial is a modern distributed version control system (VCS), written
%% mostly in Python with bits and pieces in C for performance. In this
%% chapter, I will discuss some of the decisions involved in designing
%% Mercurial's algorithms and data structures. First, allow me to go into
%% a short history of version control systems, to add necessary context.
Mercurialはモダンな分散型バージョン管理システム(VCS)で、大半はPythonで書かれている。ただ、ごく一部、パフォーマンスのためにCで書いているところもある。本章では、Mercurialのアルゴリズムやデータ構造を設計したときのいくつかの判断について説明する。まず最初に、バージョン管理システムの歴史を簡単に振り返っておこう。これが、本章を読み進めるための前提知識となる。

%% \begin{aosasect1}{ A Short History of Version Control}
\begin{aosasect1}{バージョン管理システムの簡単な歴史}

%% While this chapter is primarily about Mercurial's software
%% architecture, many of the concepts are shared with other version
%% control systems. In order to fruitfully discuss Mercurial, I'd like to
%% start off by naming some of the concepts and actions in different
%% version control systems. To put all of this in perspective, I will
%% also provide a short history of the field.
本章で主に扱うのはMercurialのアーキテクチャについてである。しかし、その概念の多くは他のバージョン管理システムと共通している。Mercurialについての議論を実のあるものにするために、まずはさまざまなバージョン管理システムの概念や動作に名前をつけるところからはじめよう。さらに、それらすべてを見渡すために、この世界の歴史についても簡単に説明する。

%% Version control systems were invented to help developers work on
%% software systems simultaneously, without passing around full copies
%% and keeping track of file changes themselves. Let's generalize from
%% software source code to any tree of files. One of the primary
%% functions of version control is to pass around changes to the
%% tree. The basic cycle is something like this:
バージョン管理システムが作られたのは、複数人によるソフトウェアシステムの開発作業を支援するためだった。ソースの完全なコピーをやりとりして変更履歴を各自で管理させるなどということをしなくて済むように、と作られたのだ。ここで、単なるソフトウェアのソースコードだけではなく、任意のファイルツリーに一般化して考えよう。バージョン管理システムの主要機能のひとつは、変更をツリーに渡すことだ。基本的な流れは、このようになる。

\begin{aosaenumerate}

  %% \item Get the latest tree of files from someone else
  \item 最新のファイルツリーを、どこか別の場所から取得する

  %% \item Work on a set of changes to this version of the tree
  \item このバージョンのツリー上で、何らかの変更を加える

  %% \item Publish the changes so that others can retrieve them
  \item 変更内容をどこかに公開し、他の人がそれを取得できるようにする

\end{aosaenumerate}

%% \noindent
%% The first action, to get a local tree of files, is called a
%% \emph{checkout}. The store where we retrieve and publish our changes
%% is called a \emph{repository}, while the result of the checkout is
%% called a \emph{working directory}, \emph{working tree}, or
%% \emph{working copy}. Updating a working copy with the latest files
%% from the repository is simply called \emph{update}; sometimes this
%% requires \emph{merging}, i.e., combining changes from different users
%% in a single file. A diff command allows us to review changes between
%% two revisions of a tree or file, where the most common mode is to
%% check the local (unpublished) changes in your working copy. Changes
%% are published by issuing a \emph{commit} command, which will save the
%% changes from the working directory to the repository.
\noindent
最初の操作、つまりファイルツリーをローカルに取得する作業のことを\emph{チェックアウト}と呼ぶ。データの取得元であり、かつ変更点の公開先でもある格納場所のことは\emph{リポジトリ}と呼び、チェックアウトしたもののことは\emph{作業ディレクトリ}あるいは\emph{作業ツリー}、\emph{作業コピー}などと呼ぶ。作業コピーの内容をリポジトリ上の最新の状態に更新することは、単に\emph{更新}と呼ぶ。このとき、場合によっては\emph{マージ}が必要になることもある。マージとは、同一ファイル上での別のユーザーによる変更をとりまとめることだ。diffコマンドを使うと、ツリーあるいはファイルについて複数のリビジョン間での変更点を確認できる。最もよくある使いかたは、作業コピー上にあるローカルの(まだ公開していない)変更を確認することだ。変更を公開するには\emph{commit}コマンドを実行する。これは、作業ディレクトリ上での変更をリポジトリに記録する。

%% \begin{aosasect2}{Centralized Version Control}
\begin{aosasect2}{中央集中型バージョン管理}

%% The first version control system was the Source Code Control System,
%% SCCS, first described in 1975. It was mostly a way of saving deltas to
%% single files that was more efficient than just keeping around copies,
%% and didn't help with publishing these changes to others. It was
%% followed in 1982 by the Revision Control System, RCS, which was a more
%% evolved and free alternative to SCCS (and which is still being
%% maintained by the GNU project).
バージョン管理システムの元祖はSource Code Control Systemだ。略してSCCSと呼ばれるこのシステムが最初に登場したのは1975年のことだった。差分をひとつのファイルに記録するという方式でバージョンを管理しており、各バージョンのコピーを取っておくよりも効率的だった。その変更を他人に公開する仕組みは用意されていなかった。その後1982年に登場したRevision Control System(略してRCS)は、さらに進化しており、SCCSの代替として使えるフリーソフトウェアだった(RCSは、今でもGNUプロジェクトが保守を続けている)。

%% After RCS came CVS, the Concurrent Versioning System, first released
%% in 1986 as a set of scripts to manipulate RCS revision files in
%% groups. The big innovation in CVS is the notion that multiple users can
%% edit simultaneously, with merges being done after the fact
%% (concurrent edits). This also required the notion of edit conflicts.
%% Developers may only commit a new version of some file if it's based
%% on the latest version available in the repository. If there are changes
%% in the repository and in my working directory, I have to resolve any
%% conflicts resulting from those changes (edits changing the same lines).
RCSに続いて登場したのがCVS。これはConcurrent Versioning Systemの略で、1986年にリリースされた。当初は、RCSのリビジョンファイルを操作するためのスクリプト群という形式だった。CVSにおける大きなイノベーションは、複数のユーザーによる同時編集と、その後での編集のマージという概念だった。ここで、編集時の衝突という概念も登場する。開発者が何らかのファイルの新しいバージョンをコミットするためには、手元のファイルをリポジトリ内の最新版に基づいたものにしておく必要があった。リポジトリ内のファイルと作業ディレクトリ上のファイルの両方で(同じ行の)変更があった場合は、両者の変更の衝突を解消しなければならなかった。

%% CVS also pioneered the notions of \emph{branches}, which allow
%% developers to work on different things in parallel, and \emph{tags},
%% which enable naming a consistent snapshot for easy reference. While
%% CVS deltas were initially communicated via the repository on a shared
%% filesystem, at some point CVS also implemented a client-server
%% architecture for use across large networks (such as the Internet).
CVSは、\emph{ブランチ}や\emph{タグ}という概念を初めて取り入れたシステムでもある。ブランチのおかげで別々の作業を並行して行えるようになり、タグのおかげでスナップショットに名前をつけて容易に参照できるようになった。CVSの差分のやりとりは、当初は共有ファイルシステム上のリポジトリを使って行っていた。その後、CVSもクライアントサーバー型のアーキテクチャを採用し、(インターネットのような)大規模ネットワーク上でも使えるようになった。

%% In 2000, three developers got together to build a new VCS, christened
%% Subversion, with the intention of fixing some of the larger
%% warts in CVS\@. Most importantly, Subversion works on whole trees at a
%% time, meaning changes in a revisions should be atomic, consistent,
%% isolated, and durable. Subversion working copies also retain a
%% pristine version of the checked out revision in the working directory,
%% so that the common diff operation (comparing the local tree against
%% a checked-out changeset) is local and thus fast.
2000年に、3人の開発者が新しいVCSの開発をはじめた。それはSubversionと名付けられ、CVSの大きな問題点を修正することを目標として開発を進めた。最も重要だったのは、Subversionがツリー全体を一括して扱うことだった。つまり、リビジョン間での変更はアトミックであり、一貫性があってそれぞれ隔離されており、永続するということだ。Subversionの作業コピーには、作業ディレクトリのリビジョンをチェックアウトした当初の状態が残っている。つまり、よくあるdiff操作(ローカルのツリーをチェックアウトしたときの状態と比べる作業)がローカルで高速に実行できるということだ。

%% One of the interesting concepts in Subversion is that tags and
%% branches are part of a project tree. A Subversion project is usually
%% divided into three areas: \code{tags}, \code{branches}, and
%% \code{trunk}. This design has proved very intuitive to users who were
%% unfamiliar with version control systems, although the flexibility
%% inherent in this design has caused
%% numerous problems for conversion tools, mostly because \code{tags} and
%% \code{branches} have more structural representation in other systems.
Subversionの興味深い概念のひとつが、タグやブランチもプロジェクトのツリーの一部とみなしたことである。Subversionのプロジェクトは、\code{tags}、\code{branches}そして\code{trunk}の三つのエリアに分かれていることが多い。この設計は、バージョン管理システムに不慣れなユーザーにとっては非常にわかりやすかった。しかし、この設計による柔軟性は、変換ツールを作る側にとってはさまざまな問題のもととなった。他のシステムでは、\code{タグ}や\code{ブランチ}はそれ専用の構造で表すことが多かったからである。

%% All of the aforementioned systems are said to be \emph{centralized};
%% to the extent that they even know how to exchange changes (starting
%% with CVS), they rely on some other computer to keep track of the
%% history of the repository. \emph{Distributed} version control systems
%% instead keep a copy of all or most of the repository history on each
%% computer that has a working directory of that repository.
ここまで取り上げたすべてのシステムは、いわゆる\emph{中央集中型}である。CVS以降のツールでは変更点をやりとりする方法を知っているが、それは他のコンピュータが変更の履歴を保持しているということに依存している。\emph{分散型}のバージョン管理システムは、リポジトリの履歴のすべて(あるいは大半)を各コンピュータに保持しており、そのリポジトリの作業ディレクトリも保持している。

\end{aosasect2}

%% \begin{aosasect2}{Distributed Version Control}
\begin{aosasect2}{分散型バージョン管理}

%% While Subversion was a clear improvement over CVS, there are still a
%% number of shortcomings. For one thing, in all centralized systems,
%% committing a changeset and publishing it are effectively the same
%% thing, since repository history is centralized in one place. This
%% means that committing changes without network access is
%% impossible. Secondly, repository access in centralized systems always
%% needs one or more network round trips, making it relatively slow compared
%% to the local accesses needed with distributed systems. Third, the systems
%% discussed above were not very good at tracking merges (some have since
%% grown better at it). In large groups working concurrently, it's
%% important that the version control system records what changes have
%% been included in some new revision, so that nothing gets lost and
%% subsequent merges can make use of this information. Fourth, the
%% centralization required by traditional VCSes sometimes seems
%% artificial, and promotes a single place for integration. Advocates of
%% distributed VCSes argue that a more distributed system allows for a
%% more organic organization, where developers can push around and
%% integrate changes as the project requires at each point in time.
SubversionはCVSよりもずっときれいな実装だったが、それでも弱点はいくつか残っていた。たとえば、これは中央集中型のバージョン管理システムに共通する問題だが、変更をコミットすると同時に事実上その変更が公開されてしまうという点もそのひとつだ。リポジトリの履歴が中央で一元管理されている以上、どうしてもそうなってしまう。これはつまり、ネットワークに接続できない環境ではコミットが不可能であるということを意味する。第二に、中央集中型のシステムでリポジトリにアクセスする際には、最低一度はネットワーク上のやりとりが発生する。そのため、分散型システムの場合のローカルアクセスに比べて、比較的動作が遅くなってしまう。第三に、これまで取り上げたシステムは、どれもマージが下手である(中にはいくらかましになったものもあるが)。大規模なグループで並行作業をしていると、新しいバージョンがバージョン管理システムのどの変更を含むものかを把握することが重要となる。とりこぼしがないかを確認し、その後のマージをうまく行うためにこの情報を使うことが必要となる。第四に、昔ながらのVCSが求める中央管理は、時に人工的に見えることもある。統合のための場所を一カ所用意することになる。分散型のVCSを支持する人たちは、分散型のシステムのほうがより有機的な組織に対応できると言う。各開発者による変更のプッシュや統合を、必要に応じてその場で行えるというわけだ。

%% A number of new tools have been developed to address these needs. From
%% where I sit (the open source world), the most notable three of these
%% in 2011 are Git, Mercurial and Bazaar. Both Git and Mercurial were
%% started in 2005 when the Linux kernel developers decided to no longer
%% use the proprietary BitKeeper system. Both were started by Linux
%% kernel developers (Linus Torvalds and Matt Mackall, respectively) to
%% address the need for a version control system that could handle
%% hundreds of thousands of changesets in tens of thousands of files (for
%% example, the kernel). Both Matt and Linus were also heavily influenced
%% by the Monotone VCS\@. Bazaar was developed separately but gained
%% widespread usage around the same time, when it was adopted by
%% Canonical for use with all of their projects.
これらの問題を解決しようと、新たなツールがいろいろ登場した。私の周囲の世界(オープンソースの世界)を見る限り、2011年の時点での三大巨頭はGitとMercurialそしてBazaarである。GitとMercurialは、どちらも2005年に開発が始まった。Linuxカーネルの開発者が、プロプライエタリなBitKeeperを使わないようにすると決断したころである。どちらのツールもLinuxカーネルの開発者が最初に作り始めた(GitはLinus Torvalds、そしてMercurialはMatt Mackallだ)。何万ものファイル上で繰り広げられる何十万ものチェンジセット(そう、たとえばLinuxカーネルみたいなもの)もきちんと扱えるように作られている。MattもLinusも、Monotone VCSの影響を強く受けていた。Bazaarの開発はそれとは別に進んでいたが、GitやMercurialと同時期に広く使われるようになった。CanonicalがすべてのプロジェクトをBazaarに移行したのがちょうどこの時期である。

%% Building a distributed version control system obviously comes with
%% some challenges, many of which are inherent in any distributed
%% system. For one thing, while the source control server in centralized
%% systems always provided a canonical view of history, there is no such
%% thing in a distributed VCS\@. Changesets can be committed in parallel,
%% making it impossible to temporally order revisions in any given
%% repository.
分散型バージョン管理システムの構築にはいろいろ困難もあった。その多くは、分散型システムという性質によるものだった。一例を挙げよう。中央集中型のシステムにおけるソース管理サーバーは常に本流の履歴を提供できるが、分散型のVCSにはそもそも「本流の」履歴など存在しない。チェンジセットは各地で並行にコミットできるので、特定のリポジトリ上で一時的にリビジョンを並べることは不可能だ。

%% The solution that has been almost universally adopted is to use a
%% directed acyclic graph (DAG) of changesets instead of a linear
%% ordering (\aosafigref{fig.hg.dag}). That is, a newly committed
%% changeset is the child revision of the revision it was based on, and
%% no revision can depend on itself or its descendant revisions. In this
%% scheme, we have three special types of revisions: \emph{root
%% revisions} which have no parents (a repository can have multiple
%% roots), \emph{merge revisions} which have more than one parent, and
%% \emph{head revisions} which have no children. Each repository starts
%% from an empty root revision and proceeds from there along a line of
%% changesets, ending up in one or more heads. When two users have
%% committed independently and one of them wants to pull in the changes
%% from the other, he or she will have to explicitly merge the other's
%% changes into a new revision, which he subsequently commits as a merge
%% revision.
この問題に対して一般的に広く受け入れられている解決策は、チェンジセットを一列に並べるのではなくチェンジセットの無閉路有向グラフ(directed acyclic graph: DAG)を使うという方法だ(\aosafigref{fig.hg.dag})。つまり、新たにコミットしたチェンジセットは別のリビジョンの子リビジョンとなり、自分自身あるいは自分の子孫の子リビジョンになることはできないという構造である。この考え方を採用するために、三種類の特殊なリビジョンを用意した。親を持たないリビジョンである\emph{rootリビジョン}(ひとつのリポジトリに複数のrootがあってもかまわない)、複数の親を持つ\emph{マージリビジョン}、そして子を持たない\emph{headリビジョン}である。各リポジトリは、まず空のrootリビジョンがひとつだけある状態から始まる。それを起点としてチェンジセットが連なり、最終的にひとつあるいは複数のheadを持つことになる。二人のユーザーがそれぞれ別のコミットをしたときに、一方がもう一方のコミットを取り込みたくなったとしよう。そんな場合は、別のユーザーの変更を新しいリビジョンに明示的にマージしなければならない。この新しいリビジョンを、マージリビジョンとしてコミットする。

%% \aosafigure[275pt]{../images/mercurial/dag.eps}{Directed Acyclic Graph of Revisions}{fig.hg.dag}
\aosafigure[275pt]{../images/mercurial/dag.eps}{各リビジョンの無閉路有向グラフ}{fig.hg.dag}

%% Note that the DAG model helps solve some of the problems that are hard
%% to solve in centralized version control systems: merge revisions are used to
%% record information about newly merged branches of the DAG. The
%% resulting graph can also usefully represent a large group of parallel
%% branches, merging into smaller groups, finally merging into one
%% special branch that's considered canonical.
DAGモデルを使うと、中央集中型のバージョン管理システムでは解決が困難な問題を解決する手助けになる。つまり、マージリビジョンを使えば、新たにDAGにマージされたブランチの情報を記録できるということだ。その結果としてできあがるグラフは並行するブランチ全体の大きなまとまりもうまく表せており、それをより小さなグループにマージしたり、最終的に「本流」ブランチにまとめたりもできる。

%% This approach requires that the system keep track of the ancestry
%% relations between changesets; to facilitate exchange of changeset data,
%% this is usually done by having changesets keep track of their
%% parents. To do this, changesets obviously also need some kind of
%% identifier. While some systems use a UUID or a similar kind of scheme,
%% both Git and Mercurial have opted to use SHA1 hashes of the contents
%% of the changesets. This has the additional useful property that the
%% changeset ID can be used to verify the changeset contents. In fact,
%% because the parents are included in the hashed data, all history
%% leading up to any revision can be verified using its hash. Author
%% names, commit messages, timestamps and other changeset metadata is
%% hashed just like the actual file contents of a new revision, so that
%% they can also be verified. And since timestamps are recorded at commit
%% time, they too do not necessarily progress linearly in any given
%% repository.
この手法を使うには、バージョン管理システムがチェンジセット間の親子関係を保持している必要がある。これを実現するため、チェンジセットのデータをやりとりする際には自分の親のチェンジセットを知っている状態にしておくことになる。当然、そのためにはチェンジセットに何らかの識別子が必要となる。システムによってはUUIDやそれに類する仕組みを使った識別子を用意しているものもあるが、GitやMercurialの場合はチェンジセットの内容のSHA1ハッシュを使っている。この方式を使うと、チェンジセットのIDを使ってチェンジセットの中身が改ざんされていないことを検証できるという利点もある。実際、親の情報もハッシュされたデータに含んでいるので、どのリビジョンからであってもそのハッシュだけで履歴の正当性を検証できる。コミットの作者名やコミットメッセージ、タイムスタンプ、その他のメタデータは、新しいリビジョンの実際の内容をハッシュするのと同様にハッシュされる。つまり、メタデータも同様に検証できるということだ。また、タイムスタンプはコミット時に記録されるので、任意のリポジトリ内でリニアに進む必要もない。

%% All of this can be hard for people who have previously only used
%% centralized VCSes to get used to: there is no nice integer to globally
%% name a revision, just a 40-character hexadecimal string. Moreover,
%% there's no longer any global ordering, just a local ordering; the only
%% global ``ordering'' is a DAG instead of a line. Accidentally starting
%% a new head of development by committing against a parent revision that
%% already had another child changeset can be confusing when you're used
%% to a warning from the VCS when this kind of thing happens.
これまでに中央集中型のVCSしか使ってこなかった人たちにとっては、こういった考え方はなかなかなじめないものだ。わかりやすい番号でリビジョンを表すのでなく、単なる40文字の16進文字列を使うだって? さらに、リビジョンの並び順など存在しない。単に個々のローカルリビジョン内での並び順があるだけで、全体的な``並び順''は一直線ではなくDAGで表している。既に別の子チェンジセットを持つリビジョンに対して、新しいheadをコミットして開発を続けることもできる。慣れ親しんだ中央集中型のVCSなら、そんなことをすれば警告が出ていたことだろう。

%% Luckily, there are tools to help visualize the tree ordering, and
%% Mercurial provides an unambiguous short version of the changeset hash
%% \emph{and} a local-only linear number to aid identification. The
%% latter is a monotonically climbing integer that indicates the order in
%% which changesets have entered the clone. Since this order can be
%% different from clone to clone, it cannot be relied on for non-local
%% operations.
幸いにも、ツリーの並び順を可視化してくれるツールも存在する。またMercurialでは、チェンジセットのハッシュの(曖昧さのない)短縮版も使えるし、\emph{さらに}、ローカル限定ではあるが一連の番号でチェンジセットを識別することもできる。この一連の番号は単調増加する整数値で、クローンに投入されたチェンジセットの順番を表す。この順番はクローンごとに異なるので、リモートリポジトリに対する操作ではこの番号は使えない。

\end{aosasect2}

\end{aosasect1}

%% \begin{aosasect1}{Data Structures}
\begin{aosasect1}{データ構造}

%% Now that the concept of a DAG should be somewhat clear, let's try
%% and see how DAGs are stored in Mercurial. The DAG model is central to
%% the inner workings of Mercurial, and we actually use several different
%% DAGs in the repository storage on disk (as well as the in-memory
%% structure of the code). This section explains what they are and how
%% they fit together.
DAGの概念がわかってきたところで、それが実際どのようにMercurialに格納されているのかを見ていこう。DAGモデルはMercurialの内部動作の中核であり、いくつかの異なるDAGを使ってリポジトリをディスク上に格納している(コードのメモリ内での構造も同じだ)。このセクションではそれぞれのDAGについて説明し、さらにそれらがどのように連携するかも説明する。

%% \begin{aosasect2}{Challenges}
\begin{aosasect2}{課題}

%% Before we dive into actual data structures, I'd like to provide some
%% context about the environment in which Mercurial evolved. The first
%% notion of Mercurial can be found in an email Matt Mackall sent to the
%% Linux Kernel Mailing List on April 20, 2005. This happened shortly
%% after it was decided that BitKeeper could no longer be used for the
%% development of the kernel. Matt started his mail by outlining some
%% goals: to be simple, scalable, and efficient.
実際のデータ構造に関する話題の前に、Mercurialの成長の歴史について簡単にまとめておく。Mercurialのそもそもの始まりは、Matt Mackallが2005年4月20日にLinux Kernelメーリングリストに投稿した一通のメールだった。その何日か前に、カーネルの開発でBitKeeperを使わないようにするという決断があったころの話である。Mattはそのメールで、いくつかの目標を示した。シンプルであること、スケーラブルであること、そして効率的であること。

%% In~\cite{bib:mackall:better}, Matt claimed that a modern VCS must deal
%% with trees containing millions of files, handle millions of
%% changesets, and scale across many thousands of users creating new
%% revisions in parallel over a span of decades. Having set the goals,
%% he reviewed the limiting technology factors:
\cite{bib:mackall:better}においてMattが指摘したのは次のようなことである。今時のVCSは何百万ものファイルを含むツリーを扱う必要がある。チェンジセットの数もそれと同じくらいだろうし、何千ものユーザーが並行して新しいリビジョンを作ったりという作業を何十年ものスパンで行うことになるだろう。Mercurialが目指す目標を設定するにあたって、彼は現在の技術的な制約についてもまとめた。

\begin{aosaitemize}

  %% \item speed: CPU
  \item 速度: CPU

  %% \item capacity: disk and memory
  \item 容量: ディスクやメモリ

  %% \item bandwidth: memory, LAN, disk, and WAN
  \item 帯域: メモリ、LAN、ディスクそしてWAN

  %% \item disk seek rate
  \item ディスクのシーク率

\end{aosaitemize}

%% Disk seek rate and WAN bandwidth are the limiting factors today, and
%% should thus be optimized for. The paper goes on to review common
%% scenarios or criteria for evaluating the performance of such a system
%% at the file level:
ディスクのシーク率やWANの帯域は今でも制約となっており、最適化を要する。この論文ではさらに、この手のシステムのパフォーマンスをファイルレベルで評価する際の一般的なシナリオや制約についての考察が続く。

\begin{aosaitemize}

  %% \item Storage compression: what kind of compression is best suited
  %% to save the file history on disk? Effectively, what algorithm makes
  %% the most out of the I/O performance while preventing CPU time
  %% from becoming a bottleneck?
  \item ストレージの圧縮: ファイルの履歴をディスク上に保存するのに最適の圧縮方法は何か? どんなアルゴリズムを使えば、CPU時間をボトルネックにしない範囲でI/Oのパフォーマンスを最大化できるか?

  %% \item Retrieving arbitrary file revisions: a number of version control
  %% systems will store a given revision in such a way that a large
  %% number of older revisions must be read to reconstruct the newer one
  %% (using deltas). We want to control this to make sure that retrieving
  %% old revisions is still fast.
  \item 任意のリビジョンのファイルの取得: 多くのバージョン管理システムが採用している格納方法だと、過去のリビジョンのファイルを大量に読み込まないと新しいリビジョンを再現できない(差分を格納している)。我々としては、それを改善しつつ過去のリビジョンも高速に取得できるようにしたい。

  %% \item Adding file revisions: we regularly add new revisions. We don't
  %% want to rewrite old revisions every time we add a new one, because
  %% that would become too slow when there are many revisions.
  \item ファイルのリビジョンの追加: 新たなリビジョンの追加は頻発する。新しいリビジョンを追加するたびに古いリビジョンを上書きするようなことは避けたい。そんなことをすれば、リビジョンが増えるにつれて速度が低下するからである。

  %% \item Showing file history: we want to be able to review a history of
  %% all changesets that touched a certain file. This also allows us to
  %% do annotations (which used to be called \code{blame} in CVS but was
  %% renamed to \code{annotate} in some later systems to remove the
  %% negative connotation): reviewing the originating changeset for each
  %% line currently in a file.
  \item ファイルの履歴の表示: ある特定のファイルを変更したすべてのチェンジセットの歴史を見直せるようにしたい。そうすれば、アノテーション(あるファイルの個々の行が、どのチェンジセットで変更されたものかを確認すること)を行えるようになる(これはCVSの時代には\code{blame}と呼ばれていたが、その言葉の否定的な意味を排除するために、後のシステムでは\code{annotate}という名前に変わったものもある)。

\end{aosaitemize}

%% The paper goes on to review similar scenarios at the project level.
%% Basic operations at this level are checking out a revision, committing
%% a new revision, and finding differences in the working directory. The
%% latter, in particular, can be slow for large trees (like those of the
%% Mozilla or NetBeans projects, both of which use Mercurial for their
%% version control needs).
この論文ではさらに、同様のシナリオについてプロジェクトレベルでの考察を続ける。プロジェクトレベルでの基本的な操作といえば、あるリビジョンのチェックアウトや新たなリビジョンのコミット、そして作業ディレクトリとの差分の検出などである。差分の検出などは特に、ツリーが大きくなると速度が低下しがちだ(MozillaやNetBeansプロジェクトを見るとよい。どちらも必要に迫られたバージョン管理にMercurialを採用している)。

\end{aosasect2}

%% \begin{aosasect2}{Fast Revision Storage: Revlogs}
\begin{aosasect2}{高速リビジョンストレージ: Revlog}

%% The solution Matt came up with for Mercurial is called the \emph{revlog}
%% (short for revision log). The revlog is a way of efficiently storing
%% revisions of file contents (each with some amount of changes compared
%% to the previous version). It needs to be efficient in both access time
%% (thus optimizing for disk seeks) and storage space, guided by the common
%% scenarios outlined in the previous section. To do this, a revlog is
%% really two files on disk: an index and the data file.
MattがMercurialで用いた解決策が\emph{revlog} (revision logを縮めたもの)だ。revlog方式を使えば、各リビジョンのファイルの中身(そして、前のバージョンからの差分)を効率的に管理できる。アクセス時間を効率化(ディスクのシークを最適化)し、ストレージのスペースも効率的に使い、先に述べた一般的なシナリオをうまく扱えなければならない。そのために、revlogはディスク上ではふたつのファイルに分かれている。インデックスファイルとデータファイルだ。

\begin{table}[h!]
  \centering
  \begin{tabular}{|rl|}
    \hline
    %% 6 bytes & hunk offset \\
    6バイト & ハンクオフセット \\
    %% 2 bytes & flags \\
    2バイト & フラグ \\
    %% 4 bytes & hunk length \\
    4バイト & ハンク長 \\
    %% 4 bytes & uncompressed length \\
    4バイト & 非圧縮時の長さ \\
    %% 4 bytes & base revision \\
    4バイト & ベースリビジョン \\
    %% 4 bytes & link revision \\
    4バイト & リンクリビジョン \\
    %% 4 bytes & parent 1 revision \\
    4バイト & 親リビジョン1 \\
    %% 4 bytes & parent 2 revision \\
    4バイト & 親リビジョン2 \\
    %% 32 bytes & hash \\
    32バイト & ハッシュ値 \\
    \hline
  \end{tabular}
  %% \caption{Mercurial Record Format}
  \caption{Mercurialのレコードフォーマット}
  \label{tbl.hg.records}
\end{table}

%% The index consists of fixed-length records, whose contents are
%% detailed in \aosatblref{tbl.hg.records}. Having fixed-length records
%% is nice, because it means that having the local revision number allows
%% direct (i.e., constant-time) access to the revision: we can simply
%% read to the position (index-length~$\times$~revision) in the index
%% file, to locate the data. Separating the index from the data also
%% means we can quickly read the index data without having to seek the
%% disk through all the file data.
インデックスは固定長のレコードで構成されており、その詳細は\aosatblref{tbl.hg.records}のとおりである。固定長のレコードを使う利点は、ローカルのリビジョン番号がわかればそのリビジョンにダイレクトアクセスできる(常に一定の時間でアクセスできる)ということだ。つまり、インデックスファイルの所定の位置(インデックス長~$\times$~リビジョン)を読めば、データの場所がわかる。インデックスをデータから分離したことで、インデックスデータの読み込みが高速化した。インデックスを読む際にファイルのデータをすべてシークする必要がなくなる。

%% The hunk offset and hunk length specify a chunk of the data file to
%% read in order to get the compressed data for that revision. To get the
%% original data we have to start by reading the base revision, and apply
%% deltas through to this revision. The trick here is the decision on
%% when to store a new base revision. This decision is based on the
%% cumulative size of the deltas compared to the uncompressed length of
%% the revision (data is compressed using zlib to use even less space on
%% disk). By limiting the length of the delta chain in this way, we make
%% sure that reconstruction of the data in a given revision does not
%% require reading and applying lots of deltas.
ハンクオフセットとハンク長で指定するのは、読む込むデータファイルの量である。これを読めば、そのリビジョンの圧縮データを取得できる。元データを取得するには、まず最初にベースリビジョンを読み込んでから当該リビジョンまでの差分を適用していけばよい。ベースリビジョンをどのタイミングで更新するかについてはちょっと考慮した。このタイミングを決める基準は、累積した差分のサイズとそのリビジョンの非圧縮時のサイズの比較である(データの圧縮にはzlibを使い、ディスクスペースを節約している)。差分群のサイズをこの方式で一定に制限することで、特定のリビジョンを再構築するときの手間をできるだけ軽減している。そのおかげで、大量の差分を適用するはめになることを回避しているのだ。

%% Link revisions are used to have dependent revlogs point back to the
%% highest-level revlog (we'll talk more about this in a little bit), and
%% the parent revisions are stored using the local integer revision
%% number. Again, this makes it easy to look up their data in the
%% relevant revlog. The hash is used to save the unique identifier for
%% this changeset. We have 32 bytes instead of the 20 bytes required for
%% SHA1 in order to allow future expansion.
リンクリビジョンは、そのリビジョンが依存するrevlogを最高レベルまでたどるために利用する(あとでもう少し詳しく説明する)。そして親リビジョンには、ローカルのリビジョン番号(整数値)が格納されている。これを使えば、関連するrevlogのデータを見つけるのも容易になる。ハッシュに保存するのは、このチェンジセットを指す一意な識別子だ。SHA1ハッシュに必要なのは20バイトだが、ここでは32バイトを確保している。これは、将来の拡張性を考慮したものである。

\end{aosasect2}

%% \begin{aosasect2}{The Three Revlogs}
\begin{aosasect2}{三種類のrevlog}

%% With the revlog providing a generic structure for historic data, we
%% can layer the data model for our file tree on top of that. It consists
%% of three types of revlogs: the \emph{changelog}, \emph{manifests}, and
%% \emph{filelogs}. The changelog contains metadata for each revision,
%% with a pointer into the manifest revlog (that is, a node id for one
%% revision in the manifest revlog). In turn, the manifest is a file that
%% has a list of filenames plus the node id for each file, pointing to a
%% revision in that file's filelog. In the code, we have classes for
%% changelog, manifest, and filelog that are subclasses of the generic
%% revlog class, providing a clean layering of both concepts.
revlogが履歴データに関する汎用的な構造を提供しているので、その上位レイヤーとしてファイルツリーを表すデータモデルを作成できる。このデータモデルは次の三種類のrevlogで構成されている。\emph{changelog}、\emph{manifests}そして\emph{filelogs}だ。changelogには各リビジョンのメタデータが含まれ、さらにmanifest revlogへのポインタ(つまり、manifest revlog内のあるリビジョンのノードid)も含まれている。また、manifestファイルにはファイル名の一覧が記録されており、さらに各ファイルのノードidも含まれている。このノードidは、各ファイルのfilelog内のリビジョンを指すものである。Mercurialのコード内では、changelogやmanifestそしてfilelogを表すクラスがそれぞれ用意されている。これらはどれも汎用のrevlogクラスを継承したものであり、個々の概念をきれいに層化している。

%% \aosafigure[275pt]{../images/mercurial/revlogs.eps}{Log Structure}{fig.hg.revlog}
\aosafigure[275pt]{../images/mercurial/revlogs.eps}{ログの構造}{fig.hg.revlog}

%% A changelog revision looks like this:
changelogのリビジョンは、このようになる。

\begin{verbatim}
0a773e3480fe58d62dcc67bd9f7380d6403e26fa
Dirkjan Ochtman <dirkjan@ochtman.nl>
1276097267 -7200
mercurial/discovery.py
discovery: fix description line
\end{verbatim}

%% \noindent This is the value you get from the revlog layer; the changelog layer
%% turns it into a simple list of values. The initial line provides the
%% manifest hash, then we get author name, date and time (in the form of
%% a Unix timestamp and a timezone offset), a list of affected files, and
%% the description message. One thing is hidden here: we allow arbitrary
%% metadata in the changelog, and to stay backwards compatible we added
%% those bits to go after the timestamp.
\noindent これこそが、revlogを層化したおかげで得られる価値である。changelog層がこのようにシンプルな値のリストで表せるようになった。最初の行はmanifestのハッシュである。それに続くのは作者名、そして日付と時刻(Unixタイムスタンプとタイムゾーンオフセットをあわせた形式)、変更されたファイルの一覧、そして最後が内容を表すメッセージとなる。さらにもうひとつ隠し機能がある。実は任意のメタデータをchangelogに含めることができるのだ。過去との互換性を維持するために、メタデータはタイムスタンプの後に追加することになる。

%% Next comes the manifest:
次はmanifestだ。

\begin{verbatim}
.hgignore\x006d2dc16e96ab48b2fcca44f7e9f4b8c3289cb701
.hgsigs\x00de81f258b33189c609d299fd605e6c72182d7359
.hgtags\x00b174a4a4813ddd89c1d2f88878e05acc58263efa
CONTRIBUTORS\x007c8afb9501740a450c549b4b1f002c803c45193a
COPYING\x005ac863e17c7035f1d11828d848fb2ca450d89794
...
\end{verbatim}

%% \noindent This is the manifest revision that changeset 0a773e points to
%% (Mercurial's UI allows us to shorten the identifier to any unambiguous
%% prefix). It is a simple list of all files in the tree, one per line,
%% where the filename is followed by a NULL byte, followed by the
%% hex-encoded node id that points into the file's filelog. Directories
%% in the tree are not represented separately, but simply inferred from
%% including slashes in the file paths. Remember that the manifest is
%% diffed in storage just like every revlog, so this structure should
%% make it easy for the revlog layer to store only changed files and
%% their new hashes in any given revision. The manifest is usually
%% represented as a hashtable-like structure in Mercurial's Python code,
%% with filenames as keys and nodes as values.
\noindent このmanifestリビジョンは、changeset 0a773eが指している先である(MercurialのUIは、曖昧にならない範囲で後半を省略できるようになっている)。これはツリーないのすべてのファイルを単純にならべた一覧であり、一行がひとつのファイルを表す。各行は、先頭にファイル名があってその後にNULLバイトを置き、さらに16進エンコードしたノードidが続く。このノードidが各ファイルのfilelogを指している。ツリーに含まれるディレクトリを特別に区別することはない。しかし、ファイルのパスにスラッシュが含まれていれば、それがディレクトリであろうと判断できる。manifestはその他のrevlogと同様に差分を格納していたことを思い出そう。つまり、manifestはrevlog層から容易にアクセスできる構造でなければならない。任意のリビジョンに対して、そのリビジョンで変更があったファイルとその新しいハッシュだけを格納することになる。manifestは、通常はMercurialのPythonコードの中ではハッシュテーブル風のデータ構造で表される。ファイル名がキー、そしてノードが値である。

%% The third type of revlog is the filelog. Filelogs are stored in Mercurial's internal \code{store} directory,
%% where they're named almost exactly like the file they're tracking. The
%% names are encoded a little bit to make sure things work across all
%% major operating systems. For example, we have to deal with casefolding
%% filesystems on Windows and Mac~OS~X, specific disallowed filenames on
%% Windows, and different character encodings as used by the various
%% filesystems. As you can imagine, doing this reliably across operating
%% systems can be fairly painful. The contents of a filelog revision, on
%% the other hand, aren't nearly as interesting: just the file contents,
%% except with some optional metadata prefix (which we use for tracking
%% file copies and renames, among other minor things).
三種類めのrevlogが、filelogだ。filelogは、Mercurialの内部的な\code{store}ディレクトリに格納されている。その名前は、追跡対象のファイルとほぼ同じである。ただし完全に同じではなく、ちょっとしたエンコードを行っている。主要なOSすべてできちんと動作させるようにするためである。たとえば、WindowsやMac~OS~Xのように大文字小文字を区別しないファイルシステムも扱う必要があるし、Windowsではファイル名に使えない文字もある。また、ファイルシステムによってさまざまな文字エンコーディングが使われている。ご想像の通り、すべてのOSで確実に動作させようとするとかなり大変なことになる。一方、filelogリビジョンの中身自体は、何の変哲もないものである。単にファイルの中身をそのまま保持しており、その先頭にちょっとしたオプションのメタデータが付属しているだけである(このメタデータを使って、ファイルのコピーやリネームなどの操作を追跡する)。

%% This data model gives us complete access to the data store in a
%% Mercurial repository, but it's not always very convenient. While the
%% actual underlying model is vertically oriented (one filelog per file),
%% Mercurial developers often found themselves wanting to deal with all
%% details from a single revision, where they start from a changeset from
%% the changelog and want easy access to the manifest and filelogs from
%% that revision.  They later invented another set of classes, layered
%% cleanly on top of the revlogs, which do exactly that. These are
%% called \code{contexts}.
このデータモデルを使えばMercurialリポジトリ内に格納されているどのデータにもアクセスできるようになる。しかし、このモデルがいつでも便利だとは限らない。実際の内部モデルは垂直指向(すなわち、ファイルごとにひとつのfilelogが存在する)である。だが、Mercurialの開発者がよくやりたくなる作業は、特定のリビジョンに関してすべてのファイルの詳細を扱うというものだった。そんな場合は、まずchangelogから特定のchangesetを探し、そのリビジョンに関連するmanifestやfilelogに簡単にアクセスできるようにしたい。そんな要望に応えるため、別のクラス群が用意された。これはrevlogの上位層に位置するもので、まさに期待通りに役割を果たす。その名は\code{contexts}だ。

%% One nice thing about the way the separate revlogs are set up is the
%% ordering. By ordering appends so that filelogs get appended to first,
%% then the manifest, and finally the changelog, the repository is always
%% in a consistent state. Any process that starts reading the changelog
%% can be sure all pointers into the other revlogs are valid, which takes
%% care of a number of issues in this department. Nevertheless, Mercurial
%% also has some explicit locks to make sure there are no two processes
%% appending to the revlogs in parallel.
revlogの設定が分割されている利点のひとつが、順序づけをするときにあらわれる。順序づけをするには、まず最初にfilelogを追加し、その後にmanifestを続け、最後にchangelogを追加する。その間リポジトリは常に一貫した状態となる。changelogを読み込むあらゆるプロセスは、その他のrevlogへのすべてのポインタが有効であることを保証されていることになり、そのおかげでさまざまな問題に対応できるようになる。それでもなお、Mercurialには明示的なロックも存在する。このロックで、複数のプロセスが同時に並行してrevlogに追記できないようにしている。

\end{aosasect2}

%% \begin{aosasect2}{The Working Directory}
\begin{aosasect2}{作業ディレクトリ}

%% A final important data structure is what we call the
%% \emph{dirstate}. The dirstate is a representation of what's in the
%% working directory at any given point. Most importantly, it keeps track
%% of what revision has been checked out: this is the baseline for all
%% comparisons from the \code{status} or \code{diff} commands, and also
%% determines the parent(s) for the next changeset to be committed. The
%% dirstate will have two parents set whenever the \code{merge} command
%% has been issued, trying to merge one set of changes into the other.
最後にもうひとつ、重要なデータ構造が残っている。その名は\emph{dirstate}だ。dirstateとは、ある特定の時点で作業ディレクトリ内に何があるのかを表したものである。最も重要なこととして、dirstateはどのリビジョンがチェックアウトされているのかを保持している。これが\code{status}や\code{diff}といったコマンドでのすべての比較の基準となり、さらに次にチェックインするコミットの親を決めることになる。dirstateは、\code{merge}コマンドを発行したときには二つの親を持つことになる。そして、一方の変更群を他方にマージしようと試みる。

%% Because \code{status} and \code{diff} are very common operations (they
%% help you check the progress of what you've currently got against the
%% last changeset), the dirstate also contains a cache of the state of
%% the working directory the last time it was traversed by Mercurial.
%% Keeping track of last modified timestamps and file sizes makes it
%% possible to speed up tree traversal. We also need to keep track of the
%% state of the file: whether it's been added, removed, or merged in the
%% working directory. This will again help speed up traversing the
%% working directory, and makes it easy to get this information at commit
%% time.
\code{status}や\code{diff}はとても頻繁に使う操作なので(直近のチェンジセットから現時点でどれくらい進んでいるのかを確かめられる)、dirstateにはMercurialが最後に作業ディレクトリを走査したときの状態のキャッシュも残している。最終更新時刻とファイルサイズを追跡することで、ツリーの走査を高速化しているのだ。また、ファイルの状態も同時に追跡しなければならない。つまり、そのファイルが作業ディレクトリに追加されたのかあるいはそこから削除されたのか、変更が加わったのかといったことだ。これも作業ディレクトリの走査を高速化させ、コミット時にこれらの情報を取得しやすくしている。

\end{aosasect2}

\end{aosasect1}

%% \begin{aosasect1}{Versioning Mechanics}
\begin{aosasect1}{バージョン管理の仕組み}

%% Now that you are familiar with the underlying data model and the
%% structure of the code at the lower levels of Mercurial, let's move up
%% a little bit and consider how Mercurial implements version control
%% concepts on top of the foundation described in the previous section.
ここまでで、Mercurialの内部的なデータモデルや低レベルでのコードの構造についてなじみが出てきたことだろう。さらにもう一歩進んでみよう。ここでは、これまでに説明した基盤の上でMercurialがどのようにバージョン管理の概念を実装しているのかを考えていく。

%% \begin{aosasect2}{Branches}
\begin{aosasect2}{ブランチ}

%% Branches are commonly used to separate different lines of development
%% that will be integrated later. This might be because someone is
%% experimenting with a new approach, just to be able to always keep the
%% main line of development in a shippable state (feature branches), or
%% to be able to quickly release fixes for an old release (maintenance
%% branches). Both approaches are commonly used, and are supported by all
%% modern version control systems. While implicit branches are common in
%% DAG-based version control named branches (where the branch name is
%% saved in the changeset metadata) are not as common.
ブランチの一般的な利用法は、開発のラインを別々に分割して進めて後で統合するというものだ。その理由として考えられるのは、たとえば誰かが新しい手法を試すときに開発のメインラインは常に出荷可能な状態にしておくこと(フィーチャブランチ)、あるいは旧バージョン用のバグフィックスを素早くリリースできるようにしておくこと(保守ブランチ)などである。どちらの手法もよく使われるものであり、今時のバージョン管理システムならすべてこれらの手法に対応している。暗黙のブランチはDAGベースのバージョン管理では一般的なものだが、名前付きブランチ(ブランチ名をチェンジセットのメタデータに記録する方式)はそれほど一般的ではない。

%% Originally, Mercurial had no way to explicitly name branches. Branches
%% were instead handled by making different clones and publishing them
%% separately. This is effective, easy to understand, and especially
%% useful for feature branches, because there is little
%% overhead. However, in large projects, clones can still be quite
%% expensive: while the repository store will be hardlinked on most
%% filesystems, creating a separate working tree is slow and may require
%% a lot of disk space.
当初は、Mercurialではブランチの名前を明示することができなかった。ブランチの処理は、単に別々のクローンを作ってそれを個別に公開するというだけのことだった。これは効率的だし理解しやすく、特にフィーチャブランチに関しては非常に便利だった。というのも、ブランチを作るオーバーヘッドがほとんどなかったからである。しかし大規模なプロジェクトでは、クローンであってもかなり重たい作業となった。大半のファイルシステム上にリポジトリのハードリンクが格納されていてもなお、個別の作業ツリーを作るのには時間がかかるし大量のディスク容量を必要とする。

%% Because of these downsides, Mercurial added a second way to do
%% branches: including a branch name in the changeset metadata. A
%% \code{branch} command was added that can set the branch name for the
%% current working directory, such that that branch name will be used for
%% the next commit. The normal \code{update} command can be used to
%% update to a branch name, and a changeset committed on a branch will
%% always be related to that branch. This approach is called \emph{named
%% branches}. However, it took a few more Mercurial releases before
%% Mercurial started including a way to close these branches up
%% again (closing a branch will hide the branch from view in a list of
%% branches). Branch closing is implemented by adding an extra field in the changeset
%% metadata, stating that this changeset closes the branch. If the branch
%% has more than one head, all of them have to be closed before the
%% branch disappears from the list of branches in the repository.
これらの弱点に対応するため、Mercurialには第二のブランチ方式が追加された。チェンジセットのメタデータにブランチ名を含める方式である。\code{branch}コマンドが追加され、現在の作業ディレクトリにブランチ名を設定できるようになった。このブランチ名は、次のコミットのときに用いられる。通常の\code{update}コマンドを使ってある特定の名前のブランチにアップデートすることもできるし、ブランチ上でコミットしたチェンジセットは常にそのブランチに関連するコミットとなる。この手法は\emph{名前付きブランチ(named branches)}と呼ばれる。しかし当初はブランチを作るだけでそれを閉じる(ブランチ一覧からそのブランチを見えなくする)ことはできなかった。ブランチを閉じられるようになったのは、それから数リリース後のことだった。ブランチを閉じる機能の実装は、チェンジセットのメタデータにフィールドを追加することで行った。追加フィールドに、このチェンジセットがブランチを閉じるという情報を記録したのだ。あるブランチが複数のheadを持つ場合は、それらをすべて閉じてからでないとブランチ一覧からそのブランチを消すことはできない。

%% Of course, there's more than one way to do it.
%% Git has a different way of naming branches, using
%% references. References are names pointing to another object in the
%% Git history, usually a changeset. This means that Git's branches are
%% ephemeral: once you remove the reference, there is no trace of the
%% branch ever having existed, similar to what you would get when using a
%% separate Mercurial clone and merging it back into another clone. This
%% makes it very easy and lightweight to manipulate branches locally, and
%% prevents cluttering of the list of branches.
もちろん、何かを成し遂げる方法はたったひとつではない(there's more than one way to do it)。Gitにおける名前付きブランチの実装はMercurialとは異なり、参照を使っている。参照とはGitの歴史上で別のオブジェクト(通常はチェンジセット)を指す名前のことである。これは、Gitのブランチがその場限りの短期的なものであることを意味する。つまり、いったん参照を削除してしまえば、そこにブランチが存在した形跡は一切なくなってしまう。これはちょうど、別々のMercurialのクローンを作って、一方のクローンをもう一方にマージしたのと同じ状態だ。この方式だとローカルでのブランチの操作が非常に簡単かつ軽量になり、ブランチ一覧がごちゃごちゃすることも避けられる。

%% This way of branching turned out to be very popular, much more popular
%% than either named branches or branch clones in Mercurial. This has
%% resulted in the \code{bookmarks}q extension, which will probably be
%% folded into Mercurial in the future. It uses a simple unversioned file
%% to keep track of references. The wire protocol used to exchange
%% Mercurial data has been extended to enable communicating about
%% bookmarks, making it possible to push them around.
この方式でのブランチ管理はどんどん広まり、今や名前付きブランチ方式やMercurial風のクローンによるブランチよりもずっと幅広く使われている。その流れを受けて、Mercurialにも\code{bookmarks}拡張が用意された。将来のバージョンでおそらくMercurialに組み込まれることだろう。この拡張は、バージョン管理対象外のシンプルなファイルを使って参照を追跡する。Mercurialのデータ交換に使っているwireプロトコルを拡張してブックマークも通信できるようにし、ブックマークもプッシュできるようにした。

\end{aosasect2}

%% \begin{aosasect2}{Tags}
\begin{aosasect2}{タグ}

%% At first sight, the way Mercurial implements tags can be a bit
%% confusing. The first time you add a tag (using the \code{tag}
%% command), a file called \code{.hgtags} gets added to the repository and
%% committed. Each line in that file will contain a changeset node id and
%% the tag name for that changeset node. Thus, the tags file is treated
%% the same way as any other file in the repository.
ちょっと見た限りだと、Mercurialにおけるタグの実装は奇妙に感じることだろう。\code{tag}コマンドを使って最初にタグを追加するときに、\code{.hgtags}というファイルがリポジトリに追加され、それをコミットする。このファイルの各行には、チェンジセットのノードidとそのチェンジセットノードに対応するタグ名が記録される。このようにして、タグ情報ファイルはリポジトリ内の他のファイルとまったく同様の扱いとなるのである。

%% There are three important reasons for this. First, it must be possible
%% to change tags; mistakes do happen, and it should be possible to fix
%% them or delete the mistake. Second, tags should be part of changeset
%% history: it's valuable to see when a tag was made, by whom, and for
%% what reason, or even if a tag was changed. Third, it should be
%% possible to tag a changeset retroactively. For example, some projects
%% extensively test drive a release artifact exported from the version
%% control system before releasing it.
このようにした重要な理由が次の三つだ。まず最初に、タグは変更できなければならない。間違いは必ず発生するものだし、間違ったタグの修正や削除ができなければならない。次に、タグ自体もチェンジセットの履歴の一部でなければならない。そのタグがいつ誰によってどういう理由で作られたのか、あるいは変更されたのかといった情報を見られれば有用だ。最後に、過去のチェンジセットにさかのぼってタグを設定できなければならない。たとえば、バージョン管理システムからエクスポートしたリリース用の成果物に対して大規模なテストをしてから初めてリリースするというプロジェクトも存在する。

%% These properties all fall easily out of the \code{.hgtags} design. While some
%% users are confused by the presence of the \code{.hgtags} file in their
%% working directories, it makes integration of the tagging mechanism
%% with other parts of Mercurial (for example, synchronization with other
%% repository clones) very simple. If tags existed outside the source
%% tree (as they do in Git, for example), separate mechanisms would have
%% to exist to audit the origin of tags and to deal with conflicts from
%% (parallel) duplicate tags. Even if the latter is rare, it's nice to
%% have a design where these things are not even an issue.
これらの特性はすべて、\code{.hgtags}の設計から容易に得られる。人によっては作業ディレクトリ内に\code{.hgtags}ファイルが存在するのを見て困惑するかもしれない。しかし、そのおかげでタグ付けの仕組みとMercurialのその他の部分との統合(同じリポジトリの別のクローンとの同期など)が非常にシンプルに行えるのだ。もしタグがソースツリーとは別になっているのなら(Gitなどがそうだ)、そのタグの出自を調べたり重複したタグの衝突を解決したりするための仕組みが別途必要になる。後者の状況はめったにないかもしれないが、そもそもそんな状況が問題になりすらしない設計があるのならそっちのほうがよいだろう。

%% To get all of this right, Mercurial only ever appends new lines to the
%% \code{.hgtags} file. This also facilitates merging the file if the
%% tags were created in parallel in different clones. The newest node id
%% for any given tag always takes precedence, and adding the null node id
%% (representing the empty root revision all repositories have in common)
%% will have the effect of deleting the tag. Mercurial will also consider
%% tags from all branches in the repository, using recency calculations
%% to determine precedence among them.
これらすべてをうまく機能させるために、Mercurialは\code{.hgtags}ファイルに新しい行を追加することしかしない。これは、別々のクローンでタグが並行して作られたときのマージにも役立つ。任意のタグに対して最新のノードidが優先され、空のノードidを追加すると(空のノードidは空のrootリビジョンを表し、すべてのリポジトリに共通して存在する)、それはタグを削除するのと同じ意味になる。Mercurialはリポジトリ内のすべてのブランチのタグの関係についても考慮し、新しいタグのほうを優先する。

\end{aosasect2}

\end{aosasect1}

%% \begin{aosasect1}{General Structure}
\begin{aosasect1}{全体的な構造}

%% Mercurial is almost completely written in Python, with only a few bits
%% and pieces in C because they are critical to the performance of the
%% whole application. Python was deemed a more suitable choice for most
%% of the code because it is much easier to express high-level concepts
%% in a dynamic language like Python. Since much of the code is not
%% really critical to performance, we don't mind taking the hit in
%% exchange for making the coding easier for ourselves in most parts.
Mercurialの大半はPythonで書かれている。ごく一部でCが使われているところもあるが、これはアプリケーション全体としてのパフォーマンスを考慮したものである。そのごく一部を除いた部分では、Pythonで書くほうが適していると考えた。なぜなら、上位レベルの概念を表現するにはPythonのような動的言語のほうがずっと容易だったからである。コードの多くは特にパフォーマンスを最優先に考えたものではないが、そんなことはあまり気にしていない。それと引き替えに、大半の部分のコーディングが簡単になっているのだから。

%% A Python module corresponds to a single file of code. Modules can
%% contain as much code as needed, and are thus an important way to
%% organize code. Modules may use types or call functions from other
%% modules by explicitly importing the other modules. A directory
%% containing an \code{\_\_init\_\_.py} module is said to be a package,
%% and will expose all contained modules and packages to the Python
%% importer.
Pythonのモジュールは、各モジュールがひとつのファイルに対応している。モジュールの中には必要に応じていくらでもコードを書くことができ、このモジュールがコードの構造をまとめる鍵となる。モジュールの中で型を使ったり他のモジュールの関数を呼び出したりするときには、他のモジュールを明示的にインポートすることがある。\code{\_\_init\_\_.py}モジュールを含むディレクトリはパッケージと呼ばれ、そこに含まれるすべてのモジュールやパッケージがPythonのインポーターに公開される。

%% Mercurial by default installs two packages into the Python path:
%% \code{mercurial} and \code{hgext}. The \code{mercurial} package
%% contains the core code required to run Mercurial, while \code{hgext}
%% contains a number of extensions that were deemed useful enough to be
%% delivered alongside the core. However, they must still be enabled by
%% hand in a configuration file if desired (which we will discuss later.)
MercurialがデフォルトでインストールするPythonのパッケージは\code{mercurial}と\code{hgext}の二つである。\code{mercurial}パッケージにはMercurialを実行するために必要なコアコードが含まれており、もう一方の\code{hgext}にはさまざまな拡張機能が含まれている。コアと一緒に配布すると有用だろうと思われるものである。しかし、これらの拡張を使いたい場合は、設定ファイルを自分で編集して拡張を有効化させなければならない(詳細は後述する)。

%% To be clear, Mercurial is a command-line application. This means that
%% we have a simple interface: the user calls the \code{hg} script with a
%% command. This command (like \code{log}, \code{diff} or \code{commit})
%% may take a number of options and arguments; there are also some
%% options that are valid for all commands. Next, there are three
%% different things that can happen to the interface.
念のために言うが、Mercurialはコマンドラインアプリケーションである。つまり、インターフェイスはシンプルなものだということである。ユーザーは、\code{hg}スクリプトにコマンドを指定して呼び出すことになる。各種コマンド(\code{log}や\code{diff}、あるいは\code{commit}など)にはいくつかのオプションや引数を受け取るものもある。また、すべてのコマンドに共通するオプションもある。次に、このインターフェイスを通して起こることは次の三つに分類できる。

\begin{aosaitemize}

  %% \item \code{hg} will often output something the user asked for or show
  %% status messages
  \item \code{hg}は、ユーザーに何かを問いかけたり状態を示したりするメッセージを出力する。

  %% \item \code{hg} can ask for further input through command-line prompts
  \item \code{hg}は、コマンドラインプロンプトでさらに入力を待ち受けることもできる。

  %% \item \code{hg} may launch an external program (such as an editor for the
  %% commit message or a program to help merging code conflicts)
  \item \code{hg}は、別のプログラム(コミットメッセージ用のエディタやコードの衝突を解消するためのマージを支援するプログラムなど)を起動することもある。

\end{aosaitemize}

%% \aosafigure{../images/mercurial/modules.eps}{Import Graph}{fig.hg.importgraph}
\aosafigure{../images/mercurial/modules.eps}{インポートグラフ}{fig.hg.importgraph}

%% The start of this process can neatly be observed from the import graph
%% in \aosafigref{fig.hg.importgraph}. All command-line arguments are
%% passed to a function in the dispatch module. The first thing that
%% happens is that a \code{ui} object is instantiated. The \code{ui}
%% class will first try to find configuration files in a number of
%% well-known places (such as your home directory), and save the
%% configuration options in the \code{ui} object. The configuration files
%% may also contain paths to extensions, which must also be loaded at
%% this point. Any global options passed on the command-line are also
%% saved to the \code{ui} object at this point.
このプロセスのはじまりは、\aosafigref{fig.hg.importgraph}のインポートグラフから読み取れる。すべてのコマンドライン引数は、まずdispatchモジュールの関数に渡される。最初に行うのは\code{ui}オブジェクトのインスタンスを作ることである。\code{ui}クラスは、まず最初にいろいろな既知の場所(ホームディレクトリなど)から設定ファイルを探し、設定オプションを\code{ui}オブジェクト内に保存する。設定ファイルには拡張機能へのパスが含まれていることもある。その場合は、この時点で拡張を読み込まねばならない。コマンドラインオプションで渡されたグローバルオプションもすべて、ここで\code{ui}オブジェクトに保存される。

%% After this is done, we have to decide whether to create a repository
%% object. While most commands require a local repository (represented
%% by the \code{localrepo} class from the \code{localrepo} module), some
%% commands may work on remote repositories (either HTTP, SSH, or some
%% other registered form), while some commands can do their work without
%% referring to any repository. The latter category includes the
%% \code{init} command, for example, which is used to initialize a new
%% repository.
これが終わると、次にリポジトリオブジェクトを作るかどうかを判断しなければならない。ほとんどのコマンドはローカルリポジトリ(\code{localrepo}モジュールの\code{localrepo}クラスで表されるもの)が必要だが、なかにはリモートリポジトリ(HTTPやSSH、あるいはその他登録済みの形式でアクセスするもの)でも動作するコマンドもある。また、リポジトリを参照しなくても動作するコマンドもある。リポジトリを参照しないコマンドの例としては\code{init}があり、これは新しいリポジトリを初期化するときに使う。

%% All core commands are represented by a single function in the
%% \code{commands} module; this makes it really easy to find the code for
%% any given command. The commands module also contains a hashtable that
%% maps the command name to the function and describes the options that
%% it takes. The way this is done also allows for sharing common sets of
%% options (for example, many commands have options that look like the
%% ones the \code{log} command uses). The options description allows the
%% dispatch module to check the given options for any command, and to
%% convert any values passed in to the type expected by the command
%% function. Almost every function also gets the \code{ui} object and the
%% \code{repository} object to work with.
すべてのコアコマンドは、\code{commands}モジュール内のひとつの関数で表される。そのため、何か特定のコマンドのソースコードを探すのも容易である。commandsモジュールにはハッシュテーブルも含まれており、このハッシュテーブルではコマンド名とそれに対応する関数そしてそのオプションに関する説明を対応させている。こうすることで、一般的なオプション群(たとえば、たいていのコマンドは\code{log}コマンドのオプションと同じようなオプションを使えるようになっている)を共有できるようになる。オプションに関する説明は、dispatchモジュールがそのコマンドのオプションをチェックするときに使う。そして、渡された値をそのコマンドの関数が期待する型に変換する。ほとんどすべての関数は、\code{ui}オブジェクトと操作対象の\code{repository}オブジェクトを受け取る。

\end{aosasect1}

%% \begin{aosasect1}{Extensibility}
\begin{aosasect1}{拡張性}

Mercurialをさらに強化できるように用意されたのが、拡張を書く機能である。Pythonは比較的身につけやすい言語であり、MercurialのAPIはとてもうまく作られている(きちんとドキュメントも用意されている)。そんなこともあって「Mercurialの拡張を書きたいからPythonを勉強しはじめました」という人も多い。

%% \begin{aosasect2}{Writing Extensions}
\begin{aosasect2}{拡張機能の作成}

%% Extensions must be enabled by adding a line to one of the
%% configuration files read by Mercurial on startup; a key is provided
%% along with the path to any Python module. There are several ways to
%% add functionality:
拡張を有効にするには、Mercurialが起動時に読み込む設定ファイルの中に一行追加する必要がある。拡張を表すキーと、Pythonモジュールへのパスをそこに記述する。機能を追加するには次のようにいくつかの方法がある。

\begin{aosaitemize}

  %% \item adding new commands;
  \item 新しいコマンドの追加

  %% \item wrapping existing commands;
  \item 既存のコマンドのラッピング

  %% \item wrapping the repository used;
  \item 使用するリポジトリのラッピング

  %% \item wrap any function in Mercurial; and
  \item Mercurialの関数のラッピング

  %% \item add new repository types.
  \item 新しいリポジトリ型の追加

\end{aosaitemize}

%% Adding new commands can be done simply by adding a hashtable called
%% \code{cmdtable} to the extension module. This will get picked up by
%% the extension loader, which will add it to the commands table
%% considered when a command is dispatched. Similarly, extensions can
%% define functions called \code{uisetup} and \code{reposetup} which are
%% called by the dispatching code after the UI and repository have been
%% instantiated. One common behavior is to use a \code{reposetup}
%% function to wrap the repository in a repository subclass provided by
%% the extension. This allows the extension to modify all kinds of basic
%% behavior. For example, one extension I have written hooks into the
%% uisetup and sets the \code{ui.username} configuration property based on the
%% SSH authentication details available from the environment.
新しいコマンドを追加するには、単に\code{cmdtable}という名前のハッシュテーブルを拡張モジュールに追加するだけである。このハッシュテーブルを拡張ローダーが読み込んで、コマンドテーブルに追加する。コマンドのディスパッチ時に、このコマンドテーブルを用いる。同じく、拡張内で\code{uisetup}および\code{reposetup}関数を定義することもできる。これらはそれぞれ、UIやリポジトリのインスタンスを生成した後にディスパッチのコードから呼び出される。共通のふるまいが一つある。それは、\code{reposetup}関数を使い、拡張が提供するrepositoryのサブクラスにリポジトリをラップすることだ。こうすることで、拡張側ですべての基本的なふるまいを変更できるようになる。たとえば、私がかつて書いたある拡張では、uisetupをフックして\code{ui.username}の内容を書き換えていた。環境から取得できるSSH認証情報に基づいたユーザー名を設定していたのだ。

%% More extreme extensions can be written to add repository types. For
%% example, the \code{hgsubversion} project (not included as part of
%% Mercurial) registers a repository type for Subversion
%% repositories. This makes it possible to clone from a Subversion
%% repository almost as if it were a Mercurial repository. It's even
%% possible to push back to a Subversion repository, although there are a
%% number of edge cases because of the impedance mismatch between the two
%% systems. The user interface, on the other hand, is completely
%% transparent.
新しいリポジトリ型を追加するといった、さらに思い切った拡張を書くこともできる。たとえば\code{hgsubversion}プロジェクト(Mercurial本体には組み込まれていない)は、Subversionのリポジトリを扱うためのリポジトリ型を登録する。これを使えばSubversionのリポジトリもクローンでき、まるでMercurialのリポジトリであるかのように扱えるようになる。変更をSubversionのリポジトリにプッシュすることも可能だ。しかし両者のシステムの間にはインピーダンスミスマッチがあるため、かなりのエッジケースが存在する。一方、ユーザーインターフェイスに関しては完全に透過的になっている。

%% For those who want to fundamentally change Mercurial, there is
%% something commonly called ``monkeypatching'' in the world of dynamic
%% languages. Because extension code runs in the same address space as
%% Mercurial, and Python is a fairly flexible language with extensive
%% reflection capabilities, it's possible (and even quite easy) to modify
%% any function or class defined in Mercurial. While this can result in
%% kind of ugly hacks, it's also a very powerful mechanism. For example,
%% the \code{highlight} extension that lives in \code{hgext} modifies the
%% built-in webserver to add syntax highlighting to pages in the
%% repository browser that allow you to inspect file contents.
Mercurialを根本的に書き換えたい人には``モンキーパッチ''という手段がある。動的言語の世界ではおなじみの方法だ。拡張のコードはMercurialと同じアドレス空間で実行され、またPythonはリフレクション機能を持つ極めて柔軟な言語なので、Mercurial内部で定義されている関数やクラスの書き換えだって容易に行える。見苦しいハックになってしまう可能性もあるが、非常に強力な仕組みでもある。たとえば、\code{hgext}にある\code{highlight}拡張は、組み込みのウェブサーバーを書き換えてリポジトリブラウザにシンタックスハイライト機能を追加し、ファイルの中身を読みやすくしている。

%% There's one more way to extend Mercurial, which is much simpler:
%% \emph{aliases}. Any configuration file can define an alias as a new
%% name for an existing command with a specific group of options already
%% set. This also makes it possible to give shorter names to any
%% commands. Recent versions of Mercurial also include the ability to
%% call a shell command as an alias, so that you can design complicated
%% commands using nothing but shell scripting.
Mercurialを拡張する方法は、もう一つ存在する。よりシンプルな方法である\emph{エイリアス}だ。すべての設定ファイルでエイリアスを定義できる。エイリアスを使えば、既存のコマンドと設定済みのオプション群をあわせたものに新しい名前をつけることができる。これを使えば、既存のコマンドの短縮形を定義することもできる。最近のバージョンのMercurialでは、シェルのコマンドもエイリアスとして呼べるようになった。これを使えば、シェルスクリプトを使ってより複雑なコマンドを作ることもできる。

\end{aosasect2}

%% \begin{aosasect2}{Hooks}
\begin{aosasect2}{フック}

%% Version control systems have long provided hooks as a way for VCS
%% events to interact with the outside world. Common usage includes
%% sending off a notification to a continuous integration
%% system\footnote{See \aosachapref{s:integration}.} or updating the
%% working directory on a web server so that changes become
%% world-visible. Of course, Mercurial also includes a subsystem to
%% invoke hooks like this.
各種バージョン管理システムは、これまでもずっとフック機構を提供してきた。この仕組みを使ってVCS上でのイベントとその他の世界とのやりとりをできるようにしていたのだ。よくある使い道としては、継続的インテグレーションシステム\footnote{\aosachapref{s:integration}を参照。}に通知を送ったり、ウェブサーバー上の作業ディレクトリを更新して最新版を一般公開したりといったものがある。もちろんMercurialにも同様に、フックを起動するサブシステムが組み込まれている。

%% In fact, it again contains two variants. One is more like traditional
%% hooks in other version control systems, in that it invokes scripts in
%% the shell. The other is more interesting, because it allows users to
%% invoke Python hooks by specifying a Python module and a function name
%% to call from that module. Not only is this faster because it runs in
%% the same process, but it also hands off \code{repo} and \code{ui} objects, meaning
%% you can easily initiate more complex interactions inside the VCS.
実際のところ、フックにもまた二通りの仕組みが用意されている。一つは昔ながらの仕組みで他のバージョン管理システムにもよくあるもの、つまり、シェル内でスクリプトを実行するという仕組みだ。もう一方はもう少し興味深い仕組みである。というのも、ユーザー側でPythonのフックを起動させる仕組みとして、Pythonのモジュール名とそのモジュールから呼び出す関数名を指定させているのだ。Mercurialと同じプロセス内で動くためにより高速になるというだけでなく、この方式では\code{repo}オブジェクトや\code{ui}オブジェクトも渡せるのでVCSないでより複雑な操作を容易に行えるということになる。

%% Hooks in Mercurial can be divided in to pre-command, post-command,
%% controlling, and miscellaneous hooks. The first two are trivially
%% defined for any command by specifying a pre-\emph{command} or
%% post-\emph{command} key in the hooks section of a configuration
%% file. For the other two types, there's a predefined set of events. The
%% difference in controlling hooks is that they are run right before
%% something happens, and may not allow that event to progress further.
%% This is commonly used to validate changesets in some way on a central
%% server; because of Mercurial's distributed nature, no such checks can
%% be enforced at commit time. For example, the Python project uses a
%% hook to make sure some aspects of coding style are enforced throughout
%% the code base---if a changeset adds code in a style that is not
%% allowed, it will be rejected by the central repository.
Mercurialのフックはpre-command、post-command、controllingそしてmiscellaneousの四種類に分類できる。最初の二つは単純なもので、設定ファイルのhooksセクションにpre-\emph{command}あるいはpost-\emph{command}というキーを設定してそこに任意のコマンドを定義するだけである。残りの二つについては、定義済みのイベントが用意されているのでそれを利用する。controllingフックがその他と異なる点は、何かが起こる直前にそのフックが実行され、場合によってはそのイベントの発生を中断させることもできるというところだ。よくある利用法は、中央サーバー上で何らかの方法でチェンジセットを検証するというものだ。Mercurialは分散型のシステムなので、コミット時にはこの手のチェックをすることができない。たとえばPythonプロジェクトでは、フックを使ってコーディング規約のチェックを行っている。あるチェンジセットで追加しようとしているコードが所定のスタイルを満たしていない場合には、中央リポジトリがそれを却下するという仕組みだ。

%% Another interesting use of hooks is a pushlog, which is used by
%% Mozilla and a number of corporate organizations. A pushlog
%% records each push (since a push may contain any number of
%% changesets) and records who initiated that push and when, providing
%% a kind of audit trail for the repository.
それ以外のフックの使い道としては、プッシュログがある。これはMozillaやその他多数の企業組織で使われている。プッシュログは個々のプッシュを記録し(ひとつのプッシュには複数のチェンジセットが含まれることもある)、さらにそのプッシュを誰がいつ行ったのかも記録する。これを、そのリポジトリの監査証跡とするのだ。

\end{aosasect2}

\end{aosasect1}

%% \begin{aosasect1}{Lessons Learned}
\begin{aosasect1}{学んだこと}

%% One of the first decisions Matt made when he started to develop
%% Mercurial was to develop it in Python. Python has been great for the
%% extensibility (through extensions and hooks) and is very easy to code
%% in. It also takes a lot of the work out of being compatible across
%% different platforms, making it relatively easy for Mercurial to work
%% well across the three major OSes. On the other hand, Python is slow
%% compared to many other (compiled) languages; in particular,
%% interpreter startup is relatively slow, which is particularly bad for
%% tools that have many shorter invocations (such as a VCS) rather than
%% longer running processes.
MattがMercurialの開発を始めるにあたって最初に決めたことのひとつが、Pythonで開発するということだった。Pythonは拡張性に優れており、非常にお手軽にコードを書ける。また、さまざまなプラットフォームでの互換性もきちんと考慮されているので、Mercurialを主要三大OSで動くようにするのも比較的容易だった。その一方で、Pythonは他の(コンパイル型の)言語に比べて実行速度が遅い。特にインタプリタの起動には時間がかかる。長期間実行しつつけるプロセスならこれは気にならないが、バージョン管理システムのように短期間に何度も起動するツールにとっては問題だ。

%% An early choice was made to make it hard to modify changesets after
%% committing. Because it's impossible to change a revision without
%% modifying its identity hash, ``recalling'' changesets after having
%% published them on the public Internet is a pain, and Mercurial makes
%% it hard to do so. However, changing unpublished revisions should
%% usually be fine, and the community has been trying to make this easier
%% since soon after the release. There are extensions that try to solve
%% the problem, but they require learning steps that are not very
%% intuitive to users who have previously used basic Mercurial.
開発初期の方針として、いったんコミットした後でのチェンジセットの変更をしにくいようにした。あるリビジョンを変更するにはそのidハッシュの変更が必須になるので、いったんインターネット上に公開したチェンジセットの``取り消し''は面倒な作業となる。そこでMercurialでは、その作業が難しくなるようにしたのだ。しかし、まだ公開していないリビジョンを変更するぶんには特に問題はない。そこで、Mercurialがリリースされて間もなく、未公開のリビジョンの変更をしやすくするようコミュニティが動き出した。この問題を解決しようとする拡張も存在するが、利用方法を身につけるのが難しく、それまでふつうにMercurialを使ってきたユーザーにとってはあまり直感的ではないものだった。

%% Revlogs are good at reducing disk seeks, and the layered architecture
%% of changelog, manifest and filelogs has worked very well. Committing
%% is fast and relatively little disk space is used for revisions.
%% However, some cases like file renames aren't very efficient due to
%% the separate storage of revisions for each file; this will eventually
%% be fixed, but it will require a somewhat hacky layering violation.
%% Similarly, the per-file DAG used to help guide filelog storage isn't
%% used a lot in practice, such that some code used to administrate
%% that data could be considered to be overhead.
revlogはディスクのシーク処理を減らすのに役立ったし、changelogやmanifestそしてfilelogsのレイヤー化アーキテクチャはうまく機能した。コミットは高速に行え、各リビジョンが利用するディスク領域は比較的少なめになる。しかし、ファイルのリネームのような一部の作業は、各ファイルのリビジョンを別々に格納しているせいで効率的に行えない。最終的にはこの問題も修正されるだろうが、レイヤー構造に反するちょっとしたハックが必要になるだろう。同じく、ファイル単位のDAGを使ってfilelogストレージを管理していることから、あまり大量のファイルを扱うのは現実的ではない。大量のファイルを管理するコードの一部がオーバーヘッドになってしまっている。

%% Another core focus of Mercurial has been to make it easy to learn.  We
%% try to provide most of the required functionality in a small set of
%% core commands, with options consistent across commands. The intention
%% is that Mercurial can mostly be learned progressively, especially for
%% those users who have used another VCS before; this philosophy extends
%% to the idea that extensions can be used to customize Mercurial even
%% more for a particular use case. For this reason, the developers also
%% tried to keep the UI in line with other VCSs, Subversion in
%% particular.  Similarly, the team has tried to provide good
%% documentation, available from the application itself, with
%% cross-references to other help topics and commands. We try hard to
%% provide useful error messages, including hints of what to try instead
%% of the operation that failed.
Mercurialが重視しているもう一つのことは、使い方を簡単に身につけられるようにすることだ。必須機能の大半を少数のコアコマンド群にまとめ、各コマンドで一貫性のあるオプションを用意している。その狙いは、特に他のVCSを使ったことがあるユーザーがMercurialを段階的に学べるようにすることである。この思想の一環として、拡張機能でMercurialをカスタマイズできるようにした。単に特定の使い道にあわせて拡張するだけではなく、それ以外にも使えるようにしたのだ。この狙いがあるため、Mercurialの開発者はそのUIをできるだけ他のVCS(特にSubversion)と合わせようとしている。同様に、開発チームではドキュメントも重視している。Mercurial自身に付属するドキュメントでは、他のトピックやコマンドへのクロスリファレンスも提供されている。また、エラーメッセージも有用なものになるよう心がけており、単に「操作が失敗しました」ではなく、何をすればいいのかというヒントを提供できるようにしている。

%% Some smaller choices made can be surprising to new users. For example,
%% handling tags (as discussed in a previous section) by putting them in
%% a separate file inside the working directory is something many users
%% dislike at first, but the mechanism has some very desirable properties
%% (though it certainly has its shortcomings as well). Similarly, other
%% VCSs have opted to send only the checked out changeset and any
%% ancestors to a remote host by default, whereas Mercurial sends every
%% committed changeset the remote doesn't have. Both approaches make some
%% amount of sense, and it depends on the style of development which one
%% is the best for you.
もう少し小さめの選択の中には、新しいユーザーにとっては少しびっくりするかもしれないものもある。たとえば、タグの処理を(先のセクションで述べたように)作業ディレクトリ内の個別のファイルで扱うという方式を好まない人も多いだろう。しかしこの方式には好ましい特性もあるのだ(もちろん欠点もあるが)。また、他のVCSではチェックアウトしたチェンジセットとその先祖だけをリモートホストに送るのがデフォルトだが、Mercurialではリモートに存在しないすべてのチェンジセットを送信することを選んだ。どちらの方式にもそれなりの理由があり、あなたにとってどちらが最適かは、その開発スタイルに依存する。

%% As in any software project, there are a lot of trade-offs to be made.
%% I think Mercurial made good choices, though of course with the benefit
%% of 20/20 hindsight some other choices might have been more appropriate.
%% Historically, Mercurial seems to be part of a first generation of
%% distributed version control systems mature enough to be ready for
%% general use. I, for one, am looking forward to seeing what the next
%% generation will look like.
他のソフトウェア開発プロジェクトと同様、Mercurialの開発でもさまざまなトレードオフが発生した。Mercurialは今までもよい選択をしてきたと思っているが、今になって考えると「もっと適切な選択肢があった」と思えるものもある。歴史的には、Mercurialは一般向けに使えるようになった第一世代の分散型バージョン管理システムである。個人的には、次の世代のシステムがどのようなものになるのかを楽しみにしている。

\end{aosasect1}

\end{aosachapter}
